package com.msb.strategy.filter.impl;

import com.msb.common.constart.CacheConstant;
import com.msb.common.constart.SmsConstant;
import com.msb.common.enums.ExceptionEnums;
import com.msb.common.exception.GraceException;
import com.msb.common.model.StandardSubmit;
import com.msb.strategy.feign.BeaconCacheClient;
import com.msb.strategy.filter.StrategyFilter;
import com.msb.strategy.util.ErrorSendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @Author: lmf
 * @Create: 2025/3/13 16:50
 * @module 限制一分钟发送短信一条
 */
@Slf4j
@Service(value = "limitOneMinute")
public class LimitOneMinuteStrategyFilter implements StrategyFilter {
    @Autowired
    private BeaconCacheClient cacheClient;

    @Resource
    private ErrorSendMessage errorSendMessage;

    @Override
    public void strategy(StandardSubmit submit) {
        // 只对验证码类型进行限制
        if (!submit.getState().equals(SmsConstant.SEND_TYPE_VERIFY)) {
            return;
        }
        log.info("【限流】短信发送开始");
        // 限制发送时长
        long ONE_MINUTE_LIMIT = 60 * 1000L;
        // 限制最大发送短信条数
        Integer ONE_MINUTE_LIMIT_COUNT = 1;


        //1、基于submit获取短信的发送时间
        LocalDateTime sendTime = submit.getSendTime();

        //2、基于LocalDateTime获取到时间的毫秒值
        long sendTimeMilli = sendTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();


        //3、基于submit获取客户标识以及手机号信息
        Long clientId = submit.getClientId();
        String mobile = submit.getMobile();

        //4、优先将当前短信发送信息插入到Redis的ZSet结构中 zadd

        String flag = clientId + CacheConstant.SEPARATE + mobile;
        String key = CacheConstant.LIMIT_ONE_MINUTE + flag;
        boolean addOk = cacheClient.zadd(key, sendTimeMilli, sendTimeMilli);


        //5、如果查询失败，直接告辞，有并发情况，60s不能发送两条，直接告辞
        if (!addOk) {
            log.info("【限流】短信发送失败，请稍后重试");
            sendMes(submit, flag);
        }
        long start = sendTimeMilli - ONE_MINUTE_LIMIT;

        //6、基于zrangebyscore查询1分钟直接，是否只有当前查询的发送短信信息
        Integer count = cacheClient.zRangeByScoreCount(key, start, sendTimeMilli);

        //7、如果大于等于2条短信信息，达到了60s一条的短信限流规则，直接告辞。
        if (count > ONE_MINUTE_LIMIT_COUNT) {
            // 限制后删除，避免重复
            cacheClient.sRemove(key, sendTimeMilli);

            sendMes(submit, flag);
        }

        // 发送成功后删除前一分钟的短信记录 避免后续的无用记录堆积
        cacheClient.zRemoveRangeByScore(key, 0, start - ONE_MINUTE_LIMIT);
        log.info("【限流】短信发送成功");
    }

    private void sendMes(StandardSubmit submit, String flag) {
        submit.setErrorMessage(ExceptionEnums.ERROR_LIMIT_ONE_MINUTE.getMsg() + flag);
        errorSendMessage.sendErrorMessage(submit, ExceptionEnums.ERROR_LIMIT_ONE_MINUTE);
    }

}
